import ctypes
import sys
import time
import psutil
from ctypes import wintypes

# 检查 IsDebuggerPresent 和 CheckRemoteDebuggerPresent
def is_debugger_present_combined():
    kernel32 = ctypes.windll.kernel32
    h_process = kernel32.GetCurrentProcess()
    remote_present = wintypes.BOOL()
    kernel32.CheckRemoteDebuggerPresent(h_process, ctypes.byref(remote_present))
    return kernel32.IsDebuggerPresent() != 0 or remote_present.value != 0

# 读取 PEB 的 BeingDebugged 字节（通过 NtQueryInformationProcess）
def is_being_debugged_peb():
    PROCESS_BASIC_INFORMATION = ctypes.c_ulong * 6
    pbi = PROCESS_BASIC_INFORMATION()
    h_process = ctypes.windll.kernel32.GetCurrentProcess()
    ntdll = ctypes.windll.ntdll
    NtQueryInformationProcess = ntdll.NtQueryInformationProcess
    ret_len = ctypes.c_ulong()
    status = NtQueryInformationProcess(
        h_process, 0, ctypes.byref(pbi), ctypes.sizeof(pbi), ctypes.byref(ret_len)
    )
    if status != 0:
        return False
    peb_base = pbi[1]
    being_debugged = ctypes.c_ubyte()
    bytes_read = ctypes.c_ulong()
    ctypes.windll.kernel32.ReadProcessMemory(
        h_process,
        peb_base + 2,  # offset for BeingDebugged
        ctypes.byref(being_debugged),
        1,
        ctypes.byref(bytes_read)
    )
    return being_debugged.value != 0

# 调用 DebugBreak，若被调试器接管则不会崩溃
def detect_debug_break():
    try:
        ctypes.windll.kernel32.DebugBreak()
        return True  # 没有崩溃说明有调试器接管
    except:
        return False  # 没有调试器会崩溃（通常抓不到异常）

def get_parent_chain_names():
    names = []
    try:
        proc = psutil.Process()
        while proc:
            proc = proc.parent()
            if not proc:
                break
            name = proc.name().lower()
            names.append(name)
    except Exception as e:
        print(f"[-] 获取父进程链失败: {e}")
    return names

def is_launched_by_debugger():
    suspicious_keywords = ["ollydbg", "x64dbg", "ida", "windbg", "processhacker", "debug"]  # 可精简
    chain = get_parent_chain_names()
    print("[*] 父进程链:", " -> ".join(chain))  # 打印调试用
    return any(any(keyword in name for keyword in suspicious_keywords) for name in chain)

# 检查 sleep 是否被 Hook（时间差明显大于真实延迟）
def check_time_drift_strict():
    start = time.perf_counter()
    time.sleep(0.1)
    delta = time.perf_counter() - start
    return delta > 0.15  # 正常情况下应小于 0.11

# 检查 NtGlobalFlag 标志位
def check_nt_global_flag():
    PROCESS_BASIC_INFORMATION = ctypes.c_ulong * 6
    pbi = PROCESS_BASIC_INFORMATION()
    h_process = ctypes.windll.kernel32.GetCurrentProcess()
    ntdll = ctypes.windll.ntdll
    ret_len = ctypes.c_ulong()
    status = ntdll.NtQueryInformationProcess(
        h_process, 0, ctypes.byref(pbi), ctypes.sizeof(pbi), ctypes.byref(ret_len)
    )
    if status != 0:
        return False
    peb_base = pbi[1]
    nt_global_flag = ctypes.c_ulong()
    ctypes.windll.kernel32.ReadProcessMemory(
        h_process,
        peb_base + 0x68,  # NtGlobalFlag offset
        ctypes.byref(nt_global_flag),
        4,
        ctypes.byref(ret_len)
    )
    return nt_global_flag.value & 0x70 != 0  # 正常为 0，调试状态下为 0x70



# 综合检测函数
def anti_debug_all():
    print("[*] 正在执行反调试检测...")

    if is_debugger_present_combined():
        print("[!] 检测到调试器 (IsDebuggerPresent / RemoteDebugger)，退出")
        sys.exit(1)

    if is_being_debugged_peb():
        print("[!] PEB 被修改 (BeingDebugged 标志为真)，退出")
        sys.exit(1)

    # if detect_debug_break():
    #     print("[!] DebugBreak 未导致崩溃，可能被调试器接管，退出")
    #     sys.exit(1)

    if is_launched_by_debugger():
        print("[!] 父进程链中存在调试器痕迹，退出")
        sys.exit(1)

    if check_time_drift_strict():
        print("[!] 时间漂移异常，可能 Sleep 被 Hook，退出")
        sys.exit(1)

    if check_nt_global_flag():
        print("[!] NtGlobalFlag 标志位异常，可能处于调试状态，退出")
        sys.exit(1)

    print("[+] 未发现调试迹象，程序将继续运行。")

if __name__ == "__main__":
    anti_debug_all()
    # 你的主程序逻辑
    print("程序继续执行...")
